package account_manage

import (
	"fmt"
	"fyne.io/fyne/v2"
	"fyne.io/fyne/v2/canvas"
	"fyne.io/fyne/v2/container"
	"fyne.io/fyne/v2/data/binding"
	"fyne.io/fyne/v2/dialog"
	"fyne.io/fyne/v2/widget"
	"go.mongodb.org/mongo-driver/bson"
	"go.mongodb.org/mongo-driver/mongo/options"
	"go_gui/diy"
	"go_gui/g"
	"go_gui/gameconfig"
	"go_gui/lib"
	"golang.org/x/image/colornames"
	"strings"
	"time"
)

// getTableList 获取数据库所有表
func getTableList() []string {
	_tableList := g.Mdb.GetTableList()
	_noCopyTableList := []string{
		"gamelog", "rmbmoneylog", "apiCount", "model_log", "xlog", "fashitalog", "zhenyingtalog",
	}

	var _resTableList []string
	for _, tableName := range _tableList {
		// 这些表的数据不复制
		if lib.InSlice(tableName, _noCopyTableList) {
			continue
		}
		// 公会数据不复制
		if strings.Contains(tableName, "gonghui") || strings.Contains(tableName, "lianmeng") {
			continue
		}
		_resTableList = append(_resTableList, tableName)
	}

	return _resTableList
}

// CopyUser 拷贝玩家到内网
func CopyUser(uid string) {
	if DebugServerInfo == nil {
		diy.ShowInformation("未设置内网数据库，无法复制", AccountComp.GameView)
		return
	}

	// 内网mongo
	g.InitMongo("neiwang", gameconfig.MongoDb{
		Url:      fmt.Sprintf("mongodb://root:iamciniao@%s", DebugServerInfo.DbHost),
		PoolSize: 10,
		DbName:   DebugServerInfo.DbName,
	})

	_options := &options.FindOneOptions{}
	_options.SetProjection(map[string]bool{
		"uid":     true,
		"binduid": true,
	})
	_inUserInfo := g.DebugMdb.FindOne("userinfo", bson.M{"uid": uid}, _options)
	// 账号存在
	if len(_inUserInfo) > 0 {
		chooseDelUser(uid)
		return
	}

	// 设置内网登录binduid
	_bindUidEntry := widget.NewEntry()
	_bindUidEntry.PlaceHolder = "不设置默认用外网的"

	_copyUserFunc := func() {
		_tableList := getTableList()
		_tableListLen := len(_tableList)

		w := fyne.CurrentApp().NewWindow(fmt.Sprintf("玩家账号Copy-%s", uid))
		_showList := container.NewVBox()
		_VScroll := container.NewVScroll(_showList)
		_showCard := widget.NewCard("", "", _VScroll)
		_jdLabel := &canvas.Text{
			Text: fmt.Sprintf(" 进度: 0/%d", _tableListLen),
			TextStyle: fyne.TextStyle{
				Bold: true,
			},
			TextSize: 20,
		}

		_showUi := container.NewBorder(
			&canvas.Text{
				Text: fmt.Sprintf(" 目标数据库: %s:%s", DebugServerInfo.DbHost, DebugServerInfo.DbName),
				TextStyle: fyne.TextStyle{
					Bold: true,
				},
				TextSize: 20,
			},
			_jdLabel,
			nil,
			nil,
			container.NewGridWithColumns(1, _showCard),
		)
		_state := 0 // 0正在复制  1复制结束

		w.SetCloseIntercept(func() {
			if _state == 0 {
				diy.ShowInformation("正在Copy玩家账号!请等待Copy结束", _showUi)
				return
			}
			w.Close()
		})
		w.SetContent(_showUi)
		w.CenterOnScreen()
		w.Resize(fyne.NewSize(500, 500))
		w.Show()

		appendBindText := func(text binding.String) {
			_showList.Objects = append(_showList.Objects, widget.NewLabelWithData(text))
			_VScroll.ScrollToBottom()
			_showList.Refresh()
		}
		appendText := func(text string) {
			_showList.Objects = append(_showList.Objects, widget.NewLabel(text))
			_VScroll.ScrollToBottom()
			_showList.Refresh()
		}
		addJd := func(text string) {
			_jdLabel.Text = text
			_jdLabel.Refresh()
		}

		var _successTable []string
		// 开始账号复制
		go func() {
			var (
				_curBindUid string
				_copyErr    error
				_copyIdx    = 1
			)
			_copyStart := func(tableName string) {
				overChan := make(chan bool)
				_showText := binding.NewString()
				_showText.Set(fmt.Sprintf("正在Copy表【%s】...", tableName))
				appendBindText(_showText)

				// copy等待loading
				go func(tableName string, overChan chan bool) {
					_useTime := 0
					_loopNum := 0
					textStrList := []string{
						fmt.Sprintf("正在Copy表【%s】.    ", tableName),
						fmt.Sprintf("正在Copy表【%s】..   ", tableName),
						fmt.Sprintf("正在Copy表【%s】...  ", tableName),
					}
					_ticker := time.NewTicker(time.Millisecond * 500)
					defer _ticker.Stop()
					_curIdx := 0
					for {
						select {
						case <-_ticker.C:
							_loopNum++
							if _loopNum%2 == 0 {
								_useTime++
							}
							_showText.Set(textStrList[_curIdx] + fmt.Sprintf("耐心等待:%d秒 ⊙﹏⊙", _useTime))
							_curIdx++
							if _curIdx >= len(textStrList) {
								_curIdx = 0
							}
						case <-overChan:
							if _copyErr == nil {
								_successTable = append(_successTable, tableName)
								if _useTime > 3 {
									_showText.Set(fmt.Sprintf("正在Copy表【%s】success!! ^o^y  耗时:%d秒", tableName, _useTime))
								} else {
									_showText.Set(fmt.Sprintf("正在Copy表【%s】success!! └(^o^)┘", tableName))
								}
							} else {
								_showText.Set(fmt.Sprintf("正在Copy表【%s】fail!! ╥﹏╥...", tableName))
							}

							return
						}
					}
				}(tableName, overChan)

				// 查询玩家当前表数据
				_filter := bson.M{
					"$or": []map[string]any{
						{"uid": uid},
						{"user_uid": uid},
					},
				}
				_dataList := g.Mdb.Find(tableName, _filter)
				if len(_dataList) == 0 {
					addJd(fmt.Sprintf(" 进度: %d/%d", _copyIdx, _tableListLen))
					overChan <- true
					return
				}
				var _insertList []any
				for _, data := range _dataList {
					// # sid需要改成内网的
					if tableName == "userinfo" {
						data["sid"] = CurGameInfo.DebugSid
						data["ghid"] = ""

						// 用设置的
						if _bindUidEntry.Text != "" {
							data["binduid"] = _bindUidEntry.Text
						}

						_curBindUid = data["binduid"].(string)
					}
					_insertList = append(_insertList, data)
				}
				// 插入到内网
				_, _copyErr = g.DebugMdb.InsertMany(tableName, _insertList)
				if _copyErr != nil {
					_errMsg := _copyErr.Error()
					if strings.Contains(_errMsg, "E11000") {
						_errMsg = fmt.Sprintf("索引冲突: %v", strings.Split(_errMsg, "index: ")[1])
					}
					_errText := &canvas.Text{
						Text:  fmt.Sprintf("    Copy失败-->%s", _errMsg),
						Color: colornames.Red,
					}
					_showList.Objects = append(_showList.Objects, _errText)
					_VScroll.ScrollToBottom()
					_showList.Refresh()
					overChan <- true

					// 索引冲突强制执行清除逻辑
					if strings.Contains(_errMsg, "索引冲突") {
						countDownDelUser(uid, _showUi, w)
					}

					return
				}
				addJd(fmt.Sprintf(" 进度: %d/%d", _copyIdx, _tableListLen))
				overChan <- true
			}
			// 优先copy userinfo
			_copyStart("userinfo")
			if _copyErr == nil {
				for _, tableName := range _tableList {
					if tableName == "userinfo" {
						continue
					}
					if strings.Contains(tableName, "zhanbao") ||
						strings.Contains(tableName, "video") ||
						strings.Contains(tableName, "log") ||
						strings.Contains(tableName, "gonghui") {
						continue
					}
					_copyIdx++
					_copyStart(tableName)
					if _copyErr != nil {
						break
					}
				}
			}

			_state = 1
			// Copy成功
			if _copyErr == nil {
				// 有些玩家有些表没数据，直接拉满，主要为了显示统一
				addJd(fmt.Sprintf(" 进度: %d/%d", _tableListLen, _tableListLen))

				appendText("success!!")
				diy.ShowObjInformation(
					_showUi,
					container.NewVBox(
						widget.NewLabel("Copy成功!! 骚年，去内网上号浪起来~~~"),
						container.NewGridWithColumns(
							3,
							&widget.Label{
								Text:      "账号:",
								Alignment: fyne.TextAlignTrailing,
							},
							&widget.Entry{
								Text: _curBindUid,
							},
						),
					),
				)
			} else {
				// 失败清除插入成功的数据
				_filter := bson.M{
					"$or": []map[string]any{
						{"uid": uid},
						{"user_uid": uid},
					},
				}
				for _, tableName := range _successTable {
					g.DebugMdb.Delete(tableName, _filter)
				}
			}

		}()
	}
	_chkFunc := func() string {
		bindUid := _bindUidEntry.Text
		if bindUid == "" {
			_options2 := &options.FindOneOptions{}
			_options2.SetProjection(map[string]bool{
				"binduid": true,
			})
			_outUserInfo := g.Mdb.FindOne("userinfo", bson.M{"uid": uid}, _options2)
			bindUid = _outUserInfo["binduid"].(string)
		}
		// 检测外网binduid是否在内网存在
		if len(g.DebugMdb.FindOne("userinfo", bson.M{"binduid": bindUid}, _options)) > 0 {
			return fmt.Sprintf(fmt.Sprintf("账号【%s】在内网存在，请重新指定", bindUid))
		}
		return "success"
	}
	_form := diy.NewForm(
		AccountComp.GameView,
		_copyUserFunc,
		_chkFunc,
		"设置内网登录账号",
		true,
		diy.NewFormItem("binduid", _bindUidEntry),
	)
	_form.Resize(fyne.NewSize(380, 0))
	_form.Show()

}

// 是否删除账号重新Copy
func chooseDelUser(uid string) {
	_chooseFunc := func(flag bool) {
		// 清除
		if flag {
			DelUser(uid)
		} else {
		}
	}
	cnf := dialog.NewConfirm("警告!!!", "该账号数据已存在，是否清除重新Copy?", _chooseFunc, AccountComp.Win)
	cnf.SetDismissText("取消")
	cnf.SetConfirmText("确定")
	cnf.Show()
}

// 倒计时删除账号(主要用于索引冲突)
func countDownDelUser(uid string, parent fyne.CanvasObject, window fyne.Window) {
	_second := 5
	_msg := fmt.Sprintf("索引冲突!!执行强制清除逻辑!! 倒计时 %d", _second)
	_loading := NewLoading(_msg, 25, parent).Show()

	_ticker := time.NewTicker(time.Second * 1)
	defer _ticker.Stop()
act:
	for {
		select {
		case <-_ticker.C:
			_second -= 1
			if _second <= 0 {
				break act
			}

			if _loading != nil {
				_loading.BaseText = fmt.Sprintf("索引冲突!!执行强制清除逻辑!! 倒计时 %d", _second)
			}
		}
	}
	_loading.Hide()
	window.Close()
	DelUser(uid)
}
